using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using Microsoft.SharedSource.SqlServer.MDDE.Middleware;

namespace Microsoft.SharedSource.SqlServer.MDDE.ManagementStudio
{
    internal partial class UpgradeTemplateShowProgress : Microsoft.SharedSource.SqlServer.MDDE.ManagementStudio.UpgradeTemplateBase
    {
        private UpgradeData[] packages;
        private UpgradeData[] instances;
        private string newTemplateName;
        private string newTemplateBody;
        private XmlDocument newTemplateConfigurations;
        Dictionary<string, int> packageDictionary;
        Dictionary<string, int> instanceDictionary;

        private delegate void UpdateUi(int rowId, UpgradeStatus status, List<string> log);
        private UpdateUi updateUi;

        enum ActionType
        {
            CreateTemplate,
            CreateTemplateInstance,
            CreatePackage
        }

        class ActionDetails
        {
            internal ActionType actionType;
            internal object[] actionParameters;

            internal ActionDetails(ActionType actionType, object[] actionParameters)
            {
                this.actionType = actionType;
                this.actionParameters = actionParameters;
            }
        }

        int totalItems = 0;
        int remainingItems = 0;
        int successItems = 0;
        int errorItems = 0;

        public UpgradeTemplateShowProgress(UpgradeTemplateWizardController controller)
            : base(controller)
        {
            InitializeComponent();
        }

        private void UpgradeTemplateShowProgress_Load(object sender, EventArgs e)
        {
            updateUi = new UpdateUi(UpdateUiHandler);

            // Populate the Actions to be performed.
            this.packageDictionary = new Dictionary<string,int>();
            this.instanceDictionary = new Dictionary<string, int>();

            #region Action - Add new template.

            newTemplateName = controller.WizardConfigurations.SelectSingleNode(
                "//Form[@Name=\"GetTemplateLocation\"]/UserInput[@Name=\"NewTemplateName\"]").
                Attributes["Value"].Value;

            int newRow = dgProgress.Rows.Add(null, "Adding new template [" + newTemplateName
                + "] to the repository.", null, null);
            totalItems++;

            //// Create the tag.
            XmlNode xBody = controller.WizardConfigurations.SelectSingleNode(
                "//Form[@Name=\"GetTemplateLocation\"]/UserInput[@Name=\"TemplateBody\"]");

            newTemplateBody = xBody.Attributes["Value"].Value;

            XmlNode xConfig = controller.WizardConfigurations.SelectSingleNode(
                "//Form[@Name=\"SelectConfigurations\"]/UserInput[@Name=\"TemplateConfigurations\"]");

            newTemplateConfigurations = new XmlDocument();
            newTemplateConfigurations.LoadXml(xConfig.Attributes["Value"].Value);

            //dgProgress.Rows[newRow].Tag = new ActionDetails(ActionType.CreateTemplate, 
            //    new object[] { newTemplateName, newTemplateBody
            //    });

            #endregion
            XmlNodeList instanceList = controller.WizardConfigurations.SelectNodes(
                "//Form[@Name=\"SelectedTemplateInstances\"]/UserInput");
            instances = new UpgradeData[instanceList.Count];
            // Action - Add template instances.
            for (int i = 0; i < instanceList.Count; i++ )
            {
                XmlNode xInstance = instanceList[i];
                int rowId = dgProgress.Rows.Add(null, "Creating new instance [" +
                    xInstance.Attributes["NewTemplateInstanceName"].Value + "].", null, null);
                instances[i].oldName = xInstance.Attributes["SourceTemplateInstanceName"].Value;
                instances[i].newName = xInstance.Attributes["NewTemplateInstanceName"].Value;
                instances[i].changeXml = null;
                this.instanceDictionary.Add(instances[i].oldName, rowId);
                totalItems++;
            }

            // Action - Add packages.
            XmlNodeList packageList = controller.WizardConfigurations.SelectNodes(
                "//Form[@Name=\"SelectPackages\"]/UserInput");
            packages = new UpgradeData[packageList.Count];

            for (int i = 0; i < packageList.Count; i++ )
            {
                XmlNode xPackage = packageList[i];
                int rowId = dgProgress.Rows.Add(null, "Creating new package [" +
                    xPackage.Attributes["NewPackageName"].Value + "].", null, null);
                packages[i].oldName = xPackage.Attributes["SourcePackageName"].Value;
                packages[i].newName = xPackage.Attributes["NewPackageName"].Value;
                packages[i].changeXml = null;

                this.packageDictionary.Add(packages[i].oldName, rowId);
                totalItems++;
            }

            // Show the total actions to be performed.
            remainingItems = totalItems;
            lblTotal.Text = totalItems.ToString();
            lblRemaining.Text = remainingItems.ToString() + " Remaining";

            MDDEManager.UpgradeInstanceStatusEvent += new MDDEManager.UpgradeStatusDeletgate(this.MDDEManager_UpgradeInstanceStatusEvent);
            MDDEManager.UpgradePackageStatusEvent += new MDDEManager.UpgradeStatusDeletgate(this.MDDEManager_UpgradePackageStatusEvent);
    
            // Start processing.
            workerProgress.RunWorkerAsync();
            //workerProgress_DoWork(null, null);
        }

        private void workerProgress_DoWork(object sender, DoWorkEventArgs e)
        {
            if (this.InvokeRequired)
                this.Invoke(this.updateUi, new object[] { 0, UpgradeStatus.Started, new List<string>() });
            else
                this.UpdateUiHandler(0, UpgradeStatus.Started, new List<string>());

            // Action - Add new template.
            OperationResult result =
                MDDEManager.AddNewTemplate(controller.RepositoryConnectionString,
                newTemplateName, newTemplateBody, newTemplateConfigurations);

            if (result.SuccessStatus == true)
            {
                if(this.InvokeRequired)
                    this.Invoke(this.updateUi, new object[]{0, UpgradeStatus.Sucess, result.OperationLog});
                else
                    this.UpdateUiHandler(0, UpgradeStatus.Sucess, result.OperationLog);
            }
            else
            {
                for (int i = 0; i < dgProgress.Rows.Count; i++)
                {
                    if (this.InvokeRequired)
                        this.Invoke(this.updateUi, new object[] { i, UpgradeStatus.Fail, result.OperationLog });
                    else
                        this.UpdateUiHandler(i, UpgradeStatus.Fail, result.OperationLog);
                }
                return;
            }
            
            //Action - Upgrade Instances
            if(this.instances.Length > 0)
                result = MDDEManager.UpgradeInstances(controller.RepositoryConnectionString,
                    controller.TemplateName, newTemplateName, this.instances);

            //Action - Upgrade Packages
            if(this.packages.Length > 0)
                result = MDDEManager.UpgradePackages(controller.RepositoryConnectionString,
                    controller.TemplateName, newTemplateName, this.packages);

            //workerProgress.ReportProgress(1);
        }

        void MDDEManager_UpgradePackageStatusEvent(string name, UpgradeStatus status, List<string> log)
        {
            int rowId = this.packageDictionary[name];
            if (this.InvokeRequired)
                this.Invoke(this.updateUi, new object[] { rowId, status, log });
            else
                this.UpdateUiHandler(rowId, status, log);
            
        }

        void MDDEManager_UpgradeInstanceStatusEvent(string name, UpgradeStatus status, List<string> log)
        {
            int rowId = this.instanceDictionary[name];
            if (this.InvokeRequired)
                this.Invoke(updateUi, new object[] { rowId, status, log });
            else
                this.UpdateUiHandler(rowId, status, log);
        }
        
        private void UpdateUiHandler(int rowId, UpgradeStatus status, List<string> log)
        {
            switch (status)
            {
                case UpgradeStatus.Started:
                    dgProgress.Rows[rowId].Cells["StatusText"].Value = "In Progress";
                    break;
                case UpgradeStatus.Sucess:
                    dgProgress.Rows[rowId].Cells["StatusText"].Value = "Success";
                    this.remainingItems--;
                    this.successItems++;
                    lblSuccess.Text = this.successItems.ToString();
                    break;
                case UpgradeStatus.Fail:
                    dgProgress.Rows[rowId].Cells["StatusText"].Value = "Failure";
                    this.remainingItems--;
                    this.errorItems++;
                    lblError.Text = this.errorItems.ToString();
                    break;
            }

            if (null != log && log.Count > 0)
                dgProgress.Rows[rowId].Cells["Message"].Value = log[0];
            lblRemaining.Text = remainingItems.ToString() + " Remaining";
        }

        protected override void btnCancel_Click(object sender, EventArgs e)
        {
            MDDEManager.UpgradeInstanceStatusEvent -= new MDDEManager.UpgradeStatusDeletgate(this.MDDEManager_UpgradeInstanceStatusEvent);
            MDDEManager.UpgradePackageStatusEvent -= new MDDEManager.UpgradeStatusDeletgate(this.MDDEManager_UpgradePackageStatusEvent);
            base.btnCancel_Click(sender, e);
        }
        private void workerProgress_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

        }

        private void workerProgress_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {

        }
    }
}

